using UnityEngine;
using System.Collections;

public class GameplayCamera : Actor
{	
	public static float CAMERAEPSILON = 0.001f;

	public class CameraExtentsInfo
	{
		private float m_MinX;
		public float MinX
		{
			get { return m_MinX; }
		}
		private float m_MaxX;
		public float MaxX
		{
			get { return m_MaxX; }
		}
		private float m_MinY;
		public float MinY
		{
			get { return m_MinY; }
		}
		private float m_MaxY;
		public float MaxY
		{
			get { return m_MaxY; }
		}
		
		public CameraExtentsInfo()
		{
			m_MinX = 0f;
			m_MaxX = 0f;
			m_MinY = 0f;
			m_MaxY = 0f;
		}
		
		public CameraExtentsInfo(float i_MinX, float i_MaxX, float i_MinY, float i_MaxY)
		{
			m_MinX = i_MinX;
			m_MaxX = i_MaxX;
			m_MinY = i_MinY;
			m_MaxY = i_MaxY;
		}
	}

	public Collider2D m_LeftSide;
	public Collider2D m_RightSide;
	public float m_PlayerXThreshold;
	public float m_LerpThreshold = 0.15f;
	public float m_LerpSpeed = 2.5f;

	private Transform m_Target;
	private Vector3 m_InitialPosition;
	private Vector3 m_NewPosition;
	private Vector3 m_PreviousPosition;
	private LevelManager.LevelType m_Type;
	
	private CameraExtentsInfo m_CameraExtents;
	public CameraExtentsInfo CameraExtents
	{
		get { return m_CameraExtents; }
	}

	#region BACKTRACK/LOCK VARIABLES
	private float m_CameraLeftX;
	private float m_CameraRightX;
	private float m_LevelLeftX;
	private float m_LevelRightX;
	#endregion

	#region GIZMOS VARIABLES
	private Vector3 m_GizmoLineStartPosition;
	private Vector3 m_GizmoLineEndPosition;
	#endregion

	private Camera m_Cam;
	public Camera Cam
	{
		get { return m_Cam; }
	}

	public float LeftLimit
	{
		get { return aTransform.position.x + m_CameraExtents.MinX; }
	}

	public float RightLimit
	{
		get { return aTransform.position.x + m_CameraExtents.MaxX; }
	}

	protected override void Awake () 
	{
		base.Awake();

		m_Cam = aGameObject.camera;
		
		float verExtents = m_Cam.orthographicSize;
		float horExtents = verExtents * Screen.width / Screen.height;
		
		m_CameraExtents = new CameraExtentsInfo(-horExtents, horExtents, verExtents, -verExtents);

		m_InitialPosition = aTransform.position;
		RefManager.Instance.RegisterGameplayCamera(this);
	}

	private void Start()
	{
		SetTarget(RefManager.Instance.Player1.aTransform);

		m_NewPosition = aTransform.position;
		m_NewPosition.z = 0;

		m_NewPosition.x = m_CameraExtents.MinX - (m_LeftSide.bounds.size.x/2f);
		m_LeftSide.transform.position = m_NewPosition;
		
		m_NewPosition.x = m_CameraExtents.MaxX + (m_RightSide.bounds.size.x/2f);
		m_RightSide.transform.position = m_NewPosition;
		
		m_NewPosition = aTransform.position;
		m_PreviousPosition = aTransform.position;

		m_Type = LevelManager.LevelType.FORWARDONLY;
	}

	private void LateUpdate () 
	{
		switch(m_Type)
		{
		case LevelManager.LevelType.FORWARDONLY:
			if(m_Target.position.x > aTransform.position.x + m_PlayerXThreshold)
			{
				m_NewPosition = m_InitialPosition;
				m_NewPosition.x = m_Target.position.x - m_PlayerXThreshold;
			}
			else
			{
				m_NewPosition = aTransform.position;
			}
			break;
		case LevelManager.LevelType.LOCK:
			m_CameraRightX	= aTransform.position.x + m_CameraExtents.MaxX;
			m_LevelRightX	= LevelManager.Instance.CurrentLevel.MaxX;
			if(m_CameraRightX < m_LevelRightX)
			{
				if(m_Target.position.x > aTransform.position.x + m_PlayerXThreshold)
				{
					m_NewPosition = m_InitialPosition;
					m_NewPosition.x = m_Target.position.x - m_PlayerXThreshold;
				}
			}
			else
			{
				if(!EnemyManager.Instance.m_EnemiesPerLevel.ContainsKey(LevelManager.Instance.CurrentLevel))
				{
					m_Type = LevelManager.LevelType.FORWARDONLY;
					break;
				}

				m_NewPosition = aTransform.position;
				m_NewPosition.x = m_LevelRightX - m_CameraExtents.MaxX;
			}
			break;
		case LevelManager.LevelType.BACKTRACK:	
			m_CameraRightX	= aTransform.position.x + m_CameraExtents.MaxX;
			m_LevelRightX	= LevelManager.Instance.CurrentLevel.m_EndBackgroundVisual.bounds.max.x;
			m_CameraLeftX 	= aTransform.position.x + m_CameraExtents.MinX;
			m_LevelLeftX 	= LevelManager.Instance.CurrentLevel.m_StartBackgroundVisual.bounds.min.x;
			
			if(m_Target.position.x > aTransform.position.x + m_PlayerXThreshold)
			{
				if(m_CameraRightX < m_LevelRightX - CAMERAEPSILON)
				{
					m_NewPosition = m_InitialPosition;
					m_NewPosition.x = m_Target.position.x - m_PlayerXThreshold;
					//Debug.Log ("MOVING RIGHT!");
				}
				else
				{
					if(!EnemyManager.Instance.m_EnemiesPerLevel.ContainsKey(LevelManager.Instance.CurrentLevel))
					{
						m_Type = LevelManager.LevelType.FORWARDONLY;
						break;
					}

					m_NewPosition = aTransform.position;
					m_NewPosition.x = m_LevelRightX - m_CameraExtents.MaxX;
					//Debug.Log ("RIGHT LIMIT REACHED!");
				}
			}
			else if(m_Target.position.x < aTransform.position.x - m_PlayerXThreshold)
			{
				if(m_CameraLeftX > m_LevelLeftX + CAMERAEPSILON)
				{
					m_NewPosition = m_InitialPosition;
					m_NewPosition.x = m_Target.position.x + m_PlayerXThreshold;
					//Debug.Log ("MOVING LEFT!");
				}
				else
				{
					m_NewPosition = aTransform.position;
					m_NewPosition.x = m_LevelLeftX - m_CameraExtents.MinX;
					//Debug.Log ("LEFT LIMIT REACHED!");
				}
			}
			break;
		}

		if(Mathf.Abs(m_NewPosition.x - m_PreviousPosition.x) >= m_LerpThreshold)
		{
			aTransform.position = Vector3.MoveTowards(aTransform.position, m_NewPosition, m_LerpSpeed * Time.deltaTime);
		}
		else
		{
			aTransform.position = m_NewPosition;
		}
		m_PreviousPosition = aTransform.position;
	}

	private void OnDrawGizmos()
	{
		m_GizmoLineStartPosition = aTransform.position;
		m_GizmoLineStartPosition.x += m_PlayerXThreshold;
		m_GizmoLineStartPosition.y = 5f;
		
		m_GizmoLineEndPosition = aTransform.position;
		m_GizmoLineEndPosition.x += m_PlayerXThreshold;
		m_GizmoLineEndPosition.y = -5f;
		Gizmos.DrawLine(m_GizmoLineStartPosition, m_GizmoLineEndPosition);
		
		m_GizmoLineStartPosition = aTransform.position;
		m_GizmoLineStartPosition.x -= m_PlayerXThreshold;
		m_GizmoLineStartPosition.y = 5f;
		
		m_GizmoLineEndPosition = aTransform.position;
		m_GizmoLineEndPosition.x -= m_PlayerXThreshold;
		m_GizmoLineEndPosition.y = -5f;
		Gizmos.DrawLine(m_GizmoLineStartPosition, m_GizmoLineEndPosition);
	}

	public void SetTarget(Transform i_Target)
	{
		m_Target = i_Target;
	}

	public void SetBehaviour(LevelManager.LevelType i_Type)
	{
		m_Type = i_Type;
	}
}
